import blogcrawlerUtil;
import atomstream;
import thirdparty.feedparser;

import time;
import re;
import xml.sax;
import sys;
import logging;
import os;

updateUrl = 'http://updates.sixapart.com/atom-stream.xml';

class LiveJournalStreamFile:
    def open(self, filePath):
        self.file = '';
        self.currElement = '';
        try:
            self.file = open(filePath);
        except:
            logging.warn('LiveJournalStreamFile::open: Cant open file ' + filePath);
            return -1;
        return 0;
        
    def close(self):
        if file:
            self.file.close();
        return 0;
        
    def next(self):
        if not self.file:
            return -1;
        start = 0;
        element = '';
        while 1:
            line = self.file.readline();
            if not line:
                self.currElement = '';
                return -1;
            elif line.startswith('<feed '):
                start = 1;
                element = line;
            elif line and start:
                element += line;
            if line.startswith('</feed>'):
                start = 0;
                if element:
                    self.currElement = element;
                    return 0;
        return -1;

    def seek(self, pos):
        if self.file:
            return self.file.seek(pos);
        return -1;
            
        
    def getCurrElement(self):
        return self.currElement;
    
    def getCurrPos(self):
        if self.file:
            return self.file.tell();
        else:
            return -1;

class LiveJournalUpdateParser:
    def parse(self, filePath):
        homeUrl = '';
        posting = '';
        try:
            doc = feedparser.parse(filePath);
            homeUrl = doc.feed.link;
            entry = doc.entries[0];
            posting = BlogElements.BlogPosting();
            posting.title = entry.title;
            posting.url = entry.link;
            posting.date = time.mktime(entry.published_parsed);
            posting.description = entry.content[0].value;
        except:
            return '','';
        return homeUrl, posting; 
#        except:
#            t = str(time.time());
#            path = t + '.err.feed'
#            file = open(path, 'w');
#            file.write(text);
#            print 'ERROR: parsing text is written to',path;
#            file.close();
#            return '', '';
#        

class LiveJournalProfileParser(xml.sax.ContentHandler):
    def __init__(self):
        self.clear();
        
    def clear(self):
        self.parents = [];
        self.profile = BlogElements.BlogProfile();
        self.profile.type = 'Person';
    
    def parseUrl(self, url):
        path = 'suibian.xml';
        blogcrawlerUtil.crawlPage(path, url);
        profile = self.parse(path);
        os.remove(path);
        return profile;
    
    def parse(self, filePath):
        xml.sax.parse(filePath, self)
        return self.profile;
        
    
    def startDocument(self):
        self.clear();
        
    def startElement(self, name, attrs):
        if name == 'foaf:Group':
            self.profile.type = 'Group';
        elif name == 'ya:country':
            if attrs.has_key('dc:title'):
                self.profile.homeCountry = attrs['dc:title'];
        elif name == 'foaf:interest':
            if attrs.has_key('dc:title'):
                if self.profile.interests:
                    self.profile.interests += ', ';
                self.profile.interests += attrs['dc:title'];
        elif name == 'foaf:openid':
            if self.profile.type <> 'Person' and self.parents[-1] == 'foaf:Person':
                '';
            if attrs.has_key('rdf:resource'):
                self.profile.url = attrs['rdf:resource'];
        self.parents.append(name);
        
    def endElement(self, name):
        try:
            self.parents.__delitem__(-1);
        except:
            print self.parents;
            print name;
            sys.exit(-1);
        
    def characters(self, content):
        if len(self.parents) == 0:
            return 0;
        elif self.parents[-1] == 'foaf:nick':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.author = content;
        elif self.parents[-1] == 'foaf:name':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.realName = content;
        elif self.parents[-1] == 'foaf:dateOfBirth':
            birthday = content;
            tokens = birthday.split('-');
            if len(tokens) == 3:
                currYear = time.localtime()[0];
                self.profile.age = currYear - int(tokens[0]);
        elif self.parents[-1] == 'ya:bio':
            self.profile.bio = content;
            
class LiveJournalUserProfileParser(LiveJournalProfileParser):
    def clear(self):
        self.parents = [];
        self.profile = BlogElements.BlogUserProfile();
        self.profile.type = 'Person';
    
    def parse(self, filePath):
        try:
            xml.sax.parse(filePath, self)
        except:
            return '';
        return self.profile;
        
    
    def startDocument(self):
        self.clear();
        
    def startElement(self, name, attrs):
        if name == 'foaf:Group':
            self.profile.type = 'Group';
        elif name == 'ya:country':
            if attrs.has_key('dc:title'):
                self.profile.homeCountry = attrs['dc:title'];
        elif name == 'foaf:interest':
            if attrs.has_key('dc:title'):
                if self.profile.interests:
                    self.profile.interests += ', ';
                self.profile.interests += attrs['dc:title'];
        elif name == 'foaf:openid':
            if self.profile.type <> 'Person' and self.parents[-1] == 'foaf:Person':
                '';
            if attrs.has_key('rdf:resource'):
                self.profile.url = attrs['rdf:resource'];
        self.parents.append(name);
        
    def endElement(self, name):
        try:
            self.parents.__delitem__(-1);
        except:
            print self.parents;
            print name;
            sys.exit(-1);
        
    def characters(self, content):
        if len(content.strip()) == 0:
            return 0;
        elif self.parents[-1] == 'foaf:nick' and self.parents[-2] == 'foaf:Person' and self.parents[-3] == 'foaf:knows':
            self.profile.friendships.append(content);
        elif self.parents[-1] == 'foaf:nick':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.author = content;
        elif self.parents[-1] == 'foaf:name':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.realName = content;
        elif self.parents[-1] == 'foaf:dateOfBirth':
            birthday = content;
            tokens = birthday.split('-');
            if len(tokens) == 3:
                currYear = time.localtime()[0];
                self.profile.age = currYear - int(tokens[0]);
        elif self.parents[-1] == 'ya:bio':
            self.profile.bio = content;
            
class LiveJournalCommunityProfileParser(LiveJournalProfileParser):
    def __init__(self):
        self.clear();
        
    def clear(self):
        self.parents = [];
        self.profile = BlogElements.BlogCommunityProfile();
        self.profile.type = 'Person';
    
    def parse(self, filePath):
        try:
            xml.sax.parse(filePath, self)
        except:
            return '';
        return self.profile;
        
        
    def startDocument(self):
        self.clear();
        
    def startElement(self, name, attrs):
        if name == 'foaf:Group':
            self.profile.type = 'Group';
        elif name == 'ya:country':
            if attrs.has_key('dc:title'):
                self.profile.homeCountry = attrs['dc:title'];
        elif name == 'foaf:interest':
            if attrs.has_key('dc:title'):
                if self.profile.interests:
                    self.profile.interests += ', ';
                self.profile.interests += attrs['dc:title'];
        elif name == 'foaf:openid':
            if self.profile.type <> 'Person' and self.parents[-1] == 'foaf:Person':
                '';
            if attrs.has_key('rdf:resource'):
                self.profile.url = attrs['rdf:resource'];
        self.parents.append(name);
        
    def endElement(self, name):
        try:
            self.parents.__delitem__(-1);
        except:
            print self.parents;
            print name;
            sys.exit(-1);
        
    def characters(self, content):
        if content.strip() == '':
            return 0;
        elif self.parents[-1] == 'foaf:nick' and self.parents[-2] == 'foaf:Person' and self.parents[-3] == 'foaf:member':
            self.profile.communityships.append(content);
        elif self.parents[-1] == 'foaf:nick':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.author = content;
        elif self.parents[-1] == 'foaf:name':
            if self.profile.type <> 'Person' and self.parents[-2] == 'foaf:Person':
                return '';
            self.profile.realName = content;
        elif self.parents[-1] == 'foaf:dateOfBirth':
            birthday = content;
            tokens = birthday.split('-');
            if len(tokens) == 3:
                currYear = time.localtime()[0];
                self.profile.age = currYear - int(tokens[0]);
        elif self.parents[-1] == 'ya:bio':
            self.profile.bio = content;
                

class LiveJournalUrlFilter:
    def isValid(self, homeUrl):
        if homeUrl.count('livejournal') <> 0:
            return True;
        else:
            return False;
        
        
'''
    home url: http://exampleusername.livejournal.com/
    profile url: http://exampleusername.livejournal.com/data/foaf
    posting url: http://exampleusername.livejournal.com/postingno.html
    or 
    home url: http://community.livejournal.com/username/
    profile url: http://community.livejournal.com/username/data/foaf
    posting url: http://community.livejournal.com/username/postingno.html
'''    
class LiveJournalUrlConverter:
    def __init__(self):
        self.pattern = re.compile('http://([^\.]+).livejournal');
        self.filter = LiveJournalUrlFilter();
        
    def posting2Home(self, postingUrl):
        homeUrl = postingUrl[0:postingUrl.rfind('/')] + '/';
        return homeUrl;
        
    def home2Profile(self, homeUrl):
        profileUrl = homeUrl;
        if not homeUrl.endswith('/'):
            profileUrl += '/'
        profileUrl += 'data/foaf';
        return profileUrl;
        
    def profile2Home(self, profileUrl):
        homeUrl = profileUrl[0:profileUrl.find('data/foaf')];
        return homeUrl;
    
    def isCommunity(self, homeUrl):
        if homeUrl.count('community.livejournal.com') <> 0:
            return True;
        else:
            return False;
        
    def isUser(self, homeUrl):
        if self.filter.isValid(homeUrl) and not self.isCommunity(homeUrl):
            return True;
        else:
            return False;
        
    def getName(self, homeUrl):
        if self.isCommunity(homeUrl):
            prefix = 'community.livejournal.com/';
            pos = homeUrl.index(prefix) + len(prefix);
            name = homeUrl[pos:];
            if name.endswith('/'):
                name = name[: len(name)-1];
            return name;
        elif self.isUser(homeUrl):
            prefix = 'http://';
            suffix = '.livejournal';
            pos = homeUrl.index(suffix);
            name = homeUrl[len(prefix):pos];
            return name;
        else:
            return '';
        
    def commuityName2Home(self, name):
        url = 'http://community.livejournal.com/' + name + '/';
        return url;
    
    def userName2Home(self, name):
        url = 'http://' + name + '.livejournal.com/';
        return url; 
        
class LiveJournalStream:
    def __init__(self):
        self.url = 'http://updates.sixapart.com/atom-stream.xml';
        self.it = atomstream.connect();
        
    def next(self):
        while 1:
            element = '';
            try:
                element = self.it.next();
            except:
                logging.warn('except in getting next! reconnect......\n');
                self.it = atomstream.connect();
            if element:
                return element;
    


if __name__ == '__main__':
    import sys;
    if sys.argv[1] == '--update-parser':
        updateParser = LiveJournalUpdateParser();
        homeUrl, posting = updateParser.parse(sys.argv[2]);
        print homeUrl;
        print posting;
    elif sys.argv[1] == '--profile-url-extractor':
        homeUrl = sys.argv[2];
        profileUrlExtractor = LiveJournalProfileUrlExtractor();
        profileUrl = profileUrlExtractor.extract(homeUrl);
        print profileUrl;
    elif sys.argv[1] == '--profile-parser':
        profileParser = LiveJournalProfileParser();
        profile = profileParser.parse(sys.argv[2]);
        print profile;
    elif sys.argv[1] == '--stream':
        stream = LiveJournalStream();
        cnt = 1;
        t = time.time();
        while 1:
            stream.next();
            cnt += 1;
            if cnt % 10 == 0:
                print '\b'*100 + str(cnt), time.time() - t,
                sys.stdout.flush();
    elif sys.argv[1] == '--stream-file':
        filePath = sys.argv[2];
        elementNum = int(sys.argv[3]);
        streamFile = LiveJournalStreamFile();
        streamFile.open(filePath);
        t1 = time.time();
        cnt = 0;
        for i in range(elementNum):
            streamFile.next();
            element = streamFile.getCurrElement();
            pos = streamFile.getCurrPos();
            if not element:
                break;
#            print element,pos;
#            print '-' * 80;
            cnt += 1;
        t2 = time.time();
        print t2-t1, (t2-t1)/cnt; 
    elif sys.argv[1] == '--stream-file-parser':
        filePath = sys.argv[2];
        elementNum = int(sys.argv[3]);
        streamFile = LiveJournalStreamFile();
        updateParser = LiveJournalUpdateParser();
        streamFile.open(filePath);
        t1 = time.time();
        cnt = 0;
        for i in range(elementNum):
            streamFile.next();
            element = streamFile.getCurrElement();
            updateParser.parse(element);
            pos = streamFile.getCurrPos();
            if not element:
                break;
            cnt += 1;
        t2 = time.time();
        print t2-t1, (t2-t1)/cnt;
        
        
            
